package com.longma.server.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.longma.server.constant.enums.YuncangStateEnum;
import com.longma.server.dao.SysUserDAO;
import com.longma.server.dao.YuncangDAO;
import com.longma.server.constant.enums.ResponseCode;
import com.longma.server.dao.YuncangUserDAO;
import com.longma.server.entity.SysUser;
import com.longma.server.entity.Yuncang;
import com.longma.server.entity.YuncangUser;
import com.longma.server.exception.BusinessException;
import com.longma.server.pojo.vo.YuncangYearStatisticDataVO;
import com.longma.server.pojo.dto.AdvanceQueryConditionDTO;
import com.longma.server.pojo.dto.YuncangAddDTO;
import com.longma.server.pojo.dto.YuncangUpdateDTO;
import com.longma.server.pojo.vo.AlarmCountVO;
import com.longma.server.pojo.vo.YuncangStatisticDataVO;
import com.longma.server.service.*;
import com.longma.server.util.AddressUtil;
import com.longma.server.util.AuthContextUtil;
import com.longma.server.util.MybatisPlusPageUtil;
import com.longma.server.util.WrappersUtil;
import net.bytebuddy.implementation.bytecode.Throw;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author HAIBO
 * @since 2021-04-28
 */
@Service
public class YuncangServiceImpl  implements IYuncangService {

    private static LocalDateTime lastTimeUpdateAddress=LocalDateTime.now();

    private Integer intervalOfUpdateAddress = 30;  //設置30分鐘更新一次數據庫地址信息

    @Autowired
    private YuncangDAO yuncangDAO;

    @Autowired
    private SysUserDAO sysUserDAO;

    @Autowired
    private YuncangUserDAO yuncangUserDAO;

    @Autowired
    private IAddressTreeService addressTreeService;

    @Autowired
    private IYearDataService yearDataService;

    @Autowired
    private IAlarmRecordService alarmRecordService;

    @Autowired
    private IYuncangUserService yuncangUserService;

    @Autowired
    private ISysUserService sysUserService;

    /**
     * 云仓注册
     */
    @Override
    public Yuncang addYuncang(YuncangAddDTO addRequestDTO)  {
        // 复制
        Yuncang yuncang = new Yuncang();
        BeanUtil.copyProperties(addRequestDTO,yuncang);

        // 调用百度地图 转为省市
        String[] address = AddressUtil.obtainAddress(yuncang.getLatitude().toString(),yuncang.getLongitude().toString());
        if(address != null) {
            yuncang.setProvince(address[0]);
            yuncang.setCity(address[1]);
        }
        Yuncang yuncang1 = setYuncangUser(yuncang);
        yuncangDAO.save(yuncang1);
        yuncangUserService.addYuncangUser(yuncang1);
        // 更新地址 levels 0:省 1:市 2：区
        addressTreeService.updateAddress(address);
        return yuncang1;
    }

    /**
     * 根据云仓id删除云仓
     */
    @Override
    public boolean deleteYuncangByIds(List<Integer> ids) {
        if (!isExistIds(ids)){
            throw new BusinessException(ResponseCode.PARAM_NOT_VALID.setMessage("id不存在"));
        }
        return yuncangDAO.removeByIds(ids);
    }

    /**
     * 更新云仓
     */
    @Override
    public Yuncang updateYuncang(YuncangUpdateDTO updateRequestDTO)  {
        // 复制
        Yuncang yuncang1 = new Yuncang();
        BeanUtil.copyProperties(updateRequestDTO,yuncang1);
        Yuncang yuncang = setYuncangUser(yuncang1);
        yuncangUserService.updateYuncangUser(yuncang);

        // 設置地址更新時間間隔
        LocalDateTime curTime = LocalDateTime.now();
        Long durationOfUpdateAddress = Duration.between(lastTimeUpdateAddress,curTime).toMinutes();
        if(yuncang.getLatitude() != null && yuncang.getLongitude()!=null && durationOfUpdateAddress>= intervalOfUpdateAddress){
            String[] address = AddressUtil.obtainAddress(yuncang.getLatitude().toString(),yuncang.getLongitude().toString());
            if(address != null) {
                yuncang.setProvince(address[0]);
                yuncang.setCity(address[1]);
                // 更新完最後一個蘊藏的地址之後，重新設置最近更新時間
                Integer lastYuncangId= null;
                List<Yuncang> lastYuncangs = yuncangDAO.list(Wrappers.<Yuncang>lambdaQuery().select());
                for(Yuncang lastYuncang:lastYuncangs){
                    lastYuncangId = lastYuncang.getId();
                }
                if(yuncang.getId().equals(lastYuncangId)) {
                    lastTimeUpdateAddress = curTime;
                }
            }
        }
        yuncangDAO.updateById(yuncang);
        return yuncang;
    }


    /**
     * 更新云仓状态
     */
    @Override
    public boolean updateYuncangState(int id, YuncangStateEnum state) {
        if(!isExistId(id)){
            throw new BusinessException(ResponseCode.PARAM_NOT_VALID.setMessage("id不存在"));
        }

       return yuncangDAO.update(Wrappers.<Yuncang>lambdaUpdate().eq(Yuncang::getId,id).set(Yuncang::getState,state));
    }


    /**
     * 根据云仓id获取云仓信息
     */
    @Override
    public Yuncang getYuncang(int id) {
        if(!isExistId(id)){
            throw new BusinessException(ResponseCode.PARAM_NOT_VALID.setMessage("id不存在"));
        }
        return yuncangDAO.getById(id);
    }

    /**
     * 根据云仓id列表获取云仓运行统计数据  总发电量、总用电量、告警数等
     */
    @Override
    public Map<Integer, YuncangStatisticDataVO> getYuncangStatisticData(List<Integer> ids) {
        if(!isExistIds(ids)){
            throw new BusinessException(ResponseCode.PARAM_NOT_VALID.setMessage("id不存在"));
        }

        Map<Integer, YuncangStatisticDataVO> result = new HashMap<>();

        // 获取告警统计
        Map<Integer, AlarmCountVO>  alarmCounts = alarmRecordService.getAlarmCount(ids);

        // 云仓id -> (年 -> 年数据)
        Map<Integer,Map<Integer, YuncangYearStatisticDataVO>> map = yearDataService.getYearStatisticData(ids);

        // 遍历
        for(Map.Entry<Integer,Map<Integer, YuncangYearStatisticDataVO>> entry :  map.entrySet()){
            Integer yuncangId = entry.getKey();
            YuncangStatisticDataVO item = new YuncangStatisticDataVO();
            Double generation = 0.0;
            Double consumtion = 0.0;
            int alarmCount = 0;
            // 累加每年发电量 用电量
            for(Map.Entry<Integer, YuncangYearStatisticDataVO> data:entry.getValue().entrySet()){
                generation += data.getValue().getGeneration();
                consumtion += data.getValue().getConsumption();
            }
            item.setGeneration(generation);
            item.setConsumption(consumtion);

            // 累加告警数
            if(alarmCounts.get(yuncangId) != null){
                AlarmCountVO alarmCountVO = alarmCounts.get(yuncangId);
                alarmCount += alarmCountVO.getCriticalNum() + alarmCountVO.getImportantNum() + alarmCountVO.getNotifyNum() + alarmCountVO.getSecondaryNum();
            }
            item.setAlarmCount(alarmCount);
            item.setYuncangId(yuncangId);
            result.put(yuncangId,item);
        }

        return result;
    }


    /**
     * 分页查询 获取云仓列表
     */
    @Override
    public IPage<Yuncang> getYuncangByPage(Long pageNum, Long pageSize, Boolean all, List<AdvanceQueryConditionDTO> conditions) {
        // 获取用户关联云仓
        String loginName = AuthContextUtil.getLoginName();
        List<Integer> yuncangIds = yuncangUserService.getYuncangIds(loginName);
        if(CollUtil.isEmpty(yuncangIds)){
            return new Page<>(pageNum,pageSize,0);
        }


        LambdaQueryWrapper<Yuncang> wrapper = WrappersUtil.lambdaQuery(conditions, Yuncang.class);
        // 云仓过滤
        wrapper.in(Yuncang::getId,yuncangIds);

        Page<Yuncang> pageUser = MybatisPlusPageUtil.getPage(pageNum, pageSize, all);
        return yuncangDAO.page(pageUser, wrapper);
    }

    /**
     * 根据统计量、区域分页查询
     * @param province：省份
     * @param city:城市
     * @param sortBy：排序字段 支持consumption、generation、alarmCount
     * @param order: 排序方式  asc or desc
     */
    @Override
    public IPage<Yuncang> getYuncangByPage(Long pageNum, Long pageSize, String province, String city, String sortBy, String order) {
        Page<Yuncang> result = new Page<>(pageNum,pageSize,0);

        // 获取用户关联云仓
        List<Integer> yuncangIds = yuncangUserService.getYuncangIds(AuthContextUtil.getLoginName());

        if(CollUtil.isEmpty(yuncangIds) ){
            return result;
        }

        // 构建查询条件
        LambdaQueryWrapper<Yuncang> wrapper = Wrappers.lambdaQuery();

        // 如果省份、城市不为空 删选
        if(StrUtil.isNotBlank(province)){
            wrapper.eq(Yuncang::getProvince,province);
        }
        if(StrUtil.isNotBlank(city)){
            wrapper.eq(Yuncang::getCity,city);
        }

        // 如果指定根据发电量、用电量、告警数排序
        if(StrUtil.isNotBlank(sortBy) && StrUtil.isNotBlank(order)) {

            // 如果是发电量、用电量、告警数
            if(ReflectUtil.hasField(YuncangStatisticDataVO.class,sortBy) && !sortBy.equals("yungcangId")){
                // 根据省市筛选云仓
                if(StrUtil.isNotBlank(province) || StrUtil.isNotBlank(city)) {
                    yuncangIds = yuncangDAO.list(wrapper.select(Yuncang::getId)).stream().map(Yuncang::getId).collect(Collectors.toList());
                    if(CollUtil.isEmpty(yuncangIds)){
                        return result;
                    }
                }

                // 获取统计数据  如果云仓不存在会抛出异常
                Map<Integer,YuncangStatisticDataVO> map = getYuncangStatisticData(yuncangIds);
                List<YuncangStatisticDataVO> values = new ArrayList<>(map.values());

                // 升序排列
                if(order.equals("asc")){
                    values = values.stream().sorted((o1, o2) -> {
                        ReflectUtil.getField(o1.getClass(),sortBy);
                        Double value1 = Double.parseDouble(String.valueOf(ReflectUtil.getFieldValue(o1,sortBy)));
                        Double value2 =  Double.parseDouble(String.valueOf(ReflectUtil.getFieldValue(o2,sortBy)));
                        return value1.compareTo(value2);
                    }).collect(Collectors.toList());
                }

                // 降序排列
                if(order.equals("desc")){
                    values = values.stream().sorted((o1, o2) -> {
                        Double value1 =  Double.parseDouble(String.valueOf(ReflectUtil.getFieldValue(o1,sortBy)));
                        Double value2 =  Double.parseDouble(String.valueOf(ReflectUtil.getFieldValue(o2,sortBy)));
                        return value2.compareTo(value1);
                    }).collect(Collectors.toList());
                }

                result.setTotal(values.size());
                // 計算頁start
                long start = (pageNum-1) * pageSize;
                long end = pageNum*pageSize;
                if(end >= values.size()){
                    end =  values.size();
                }

                // 計算最大頁碼
                Long maxPageNum = new Double(Math.ceil(values.size()/pageNum)).longValue();
                if(maxPageNum < pageNum){
                    return result;
                }

                // 过滤需要的id
                yuncangIds = values.subList((int) start, (int) end).stream().map(YuncangStatisticDataVO::getYuncangId).collect(Collectors.toList());

                //查询
                Map<Integer,Yuncang> yuncangs = yuncangDAO.listByIds(yuncangIds).stream().collect(Collectors.toMap(Yuncang::getId, Function.identity()));

                // 按云仓id顺序排序
                List<Yuncang> list = new ArrayList<>();
                for(Integer yuncangId:yuncangIds){
                    list.add(yuncangs.get(yuncangId));
                }

                result.setRecords(list);
            }
            return result;
        }else{
            wrapper.in(Yuncang::getId,yuncangIds);
            Page<Yuncang> pageUser = MybatisPlusPageUtil.getPage(pageNum, pageSize, false);
            return yuncangDAO.page(pageUser, wrapper);
        }
    }

    /**
     * 判断id列表是否存在
     */
    @Override
    public boolean isExistIds(List<Integer> ids) {
        if (CollUtil.isEmpty(ids)) {
            return false;
        }
        LambdaQueryWrapper<Yuncang> wrapper = Wrappers.lambdaQuery();
        Set<Integer> productIds = new HashSet<>(ids);
        return yuncangDAO.count(wrapper.in(Yuncang::getId, productIds)) == productIds.size();
    }

    /**
     * 判断id是否存在
     */
    @Override
    public boolean isExistId(Integer id) {
        return isExistIds(Arrays.asList(id));
    }

    private Yuncang setYuncangUser(Yuncang yuncang){
        // 若设置了云仓管理员
        if(yuncang.getYuncanguserName()!=null&&(!yuncang.getYuncanguserName().equals("string"))){
            // 若设置云仓管理员但用户名不存在
            if(!sysUserService.checkUserRealName(yuncang.getYuncanguserName())){
                throw new BusinessException(ResponseCode.USER_ACCOUNT_NOT_EXIST.setMessage("用户不存在"));
            }
            // 如果未设置云仓管理员，默认设置为当前用户
        }
//        else {
//            if(null!=AuthContextUtil.getLoginName()) {
//                SysUser user = sysUserDAO.getOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getLoginName, AuthContextUtil.getLoginName()));
//                yuncang.setYuncanguserName(user.getRealName());
//            }
//        }
        return yuncang;
    }
}
